#include "snake.h"

// 全局变量定义
int maxX, maxY;
SnakeSegment snake[100];
int snakeLength = 5;
int direction = KEY_RIGHT;
int foodX, foodY;
int currScore = 0;
const int INITIAL_DELAY = 200; // 初始延迟 200ms
int delay = INITIAL_DELAY;
int HighScore = 0;
bool isMoving = false;  // 初始不移动
bool r_pressed = false; // 长按 r 状态
bool s_pressed = false; // 长按 s 状态

// 初始化ncurses
void initNcurses()
{
  setlocale(LC_ALL, ""); // 设置UTF-8支持
  initscr();
  start_color();
  init_pair(1, COLOR_GREEN, COLOR_BLACK);  // 绿色
  init_pair(2, COLOR_YELLOW, COLOR_BLACK); // 黄色
  init_pair(3, COLOR_RED, COLOR_BLACK);    // 红色（食物）
  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  curs_set(0);           // 隐藏光标
  nodelay(stdscr, TRUE); // 设置非阻塞输入
  getmaxyx(stdscr, maxY, maxX);
}

// 绘制字符蛇(欢迎界面用)
void printsnake()
{
  getmaxyx(stdscr, maxY, maxX);
  clear();
  attron(COLOR_PAIR(1)); // 绿色
  int startX = maxX / 4; // 居中
  int startY = maxY / 4;
  mvprintw(startY, startX, "  ****  ");
  mvprintw(startY + 1, startX, " *    * ");
  mvprintw(startY + 2, startX, "*      *");
  mvprintw(startY + 3, startX, "*      *");
  mvprintw(startY + 4, startX, " *    * ");
  mvprintw(startY + 5, startX, "  ****  ");
  attron(COLOR_PAIR(2)); // 黄色
  mvprintw(startY + 2, startX + 10, "SNAKE GAME");
  attroff(COLOR_PAIR(2));
  attroff(COLOR_PAIR(1));
  refresh();
}

// 游戏说明界面
void explation(bool startGame)
{
  clear();
  mvprintw(0, 0, "=== 贪吃蛇游戏说明 ===");
  mvprintw(2, 0, "1. 使用方向键（上下左右）控制蛇移动。");
  mvprintw(3, 0, "2. 吃到红色食物(O)得分并增长，加速移动。");
  mvprintw(4, 0, "3. 撞墙或咬到自己游戏结束。");
  mvprintw(5, 0, "4. 按 r 加速，s 减速。");
  if (startGame)
  {
    mvprintw(7, 0, "按任意键进入游戏（方向键开始移动）...");
    refresh();
    nodelay(stdscr, FALSE); // 临时启用阻塞输入
    getch();
    nodelay(stdscr, TRUE); // 恢复非阻塞输入
    clear();
    createMap();
    initsnake();
    createfood();
    scoreandtips();
    mvprintw(maxY, 1, "按方向键开始移动"); // 显示在最底部
    refresh();
  }
  else
  {
    mvprintw(7, 0, "按任意键返回主界面...");
    refresh();
    nodelay(stdscr, FALSE); // 临时启用阻塞输入
    getch();
    nodelay(stdscr, TRUE); // 恢复非阻塞输入
    clear();
    printsnake();
  }
}

// 显示最高分
void showRank()
{
  File_out(); // 确保使用最新 HighScore
  clear();
  mvprintw(0, 0, "=== 查看最高分 ===");
  mvprintw(2, 0, "最高分: %d", HighScore);
  mvprintw(4, 0, "按任意键返回主界面...");
  refresh();
  nodelay(stdscr, FALSE); // 临时启用阻塞输入
  getch();
  nodelay(stdscr, TRUE); // 恢复非阻塞输入
  clear();
  printsnake();
}

// 游戏结束显示
void showGameOver(int initialHighScore, bool newRecord, bool &gameRunning)
{
  File_out(); // 重新加载最新 HighScore
  clear();
  mvprintw(0, 0, "=== 游戏结束 ===");
  mvprintw(2, 0, "当前得分: %d", currScore);
  mvprintw(3, 0, "最高分: %d", initialHighScore);
  if (newRecord)
  {
    mvprintw(4, 0, "创纪录啦！最高分被你刷新啦，真棒！！！");
  }
  else
  {
    mvprintw(4, 0, "继续努力吧~你离最高分还差: %d", initialHighScore - currScore);
  }
  mvprintw(6, 0, "1. 再来一次  2. 返回主界面");
  mvprintw(7, 0, "请输入选择(1-2): ");
  refresh();
  nodelay(stdscr, FALSE); // 临时启用阻塞输入
  char choice = getch();
  nodelay(stdscr, TRUE); // 恢复非阻塞输入
  if (choice == '1')
  {
    restartGame();
    gameRunning = true; // 继续游戏循环
  }
  else if (choice == '2')
  {
    gameRunning = false; // 结束游戏循环，返回主界面
  }
  else
  {
    mvprintw(8, 0, "输入错误，请按任意键返回！");
    refresh();
    nodelay(stdscr, FALSE); // 等待按键
    getch();
    nodelay(stdscr, TRUE);
    showGameOver(initialHighScore, newRecord, gameRunning);
  }
}

// 从文件中读取最高分
void File_out()
{
  FILE *file = fopen("save.txt", "r");
  if (file)
  {
    fscanf(file, "%d", &HighScore);
    fclose(file);
  }
  else
  {
    HighScore = 0;
  }
}

// 绘制得分和小提示
void scoreandtips()
{
  getmaxyx(stdscr, maxY, maxX); // 重新获取终端大小
  // maxY - 2 行显示得分
  mvprintw(maxY - 2, 1, "得分: %d  最高分: %d", currScore, HighScore);
  // maxY - 1 行显示提示
  mvprintw(maxY - 1, 1, "方向键控制，ESC退出，r加速，s减速");
  refresh();
}

// 重启游戏
void restartGame()
{
  snakeLength = 5;
  currScore = 0;
  delay = INITIAL_DELAY;
  direction = KEY_RIGHT;
  isMoving = false;  // 确保蛇静止
  r_pressed = false; // 重置按键状态
  s_pressed = false;
  clear();
  createMap();                           // 直接创建地图
  initsnake();                           // 初始化蛇
  createfood();                          // 创建食物
  scoreandtips();                        // 更新得分和提示
  mvprintw(maxY, 1, "按方向键开始移动"); // 显示初始提示
  refresh();
}

// 欢迎界面及菜单
void welcometogame()
{
  initNcurses();
  File_out();
  printsnake();
  int menuY = maxY / 2;
  int menuX = maxX / 4;
  mvprintw(menuY, menuX, "1. 开始游戏");
  mvprintw(menuY + 1, menuX, "2. 游戏说明");
  mvprintw(menuY + 2, menuX, "3. 查看最高分");
  mvprintw(menuY + 3, menuX, "4. 退出");
  mvprintw(menuY + 5, menuX, "请输入你的选择(1-4): ");
  refresh();
  while (true)
  {
    nodelay(stdscr, FALSE); // 阻塞输入，防止闪烁
    char choice = getch();
    nodelay(stdscr, TRUE); // 恢复非阻塞输入
    clear();
    if (choice == '1')
    {
      bool gameRunning = true;
      int initialHighScore = HighScore; // 保存初始最高分
      explation(true);                  // 进入游戏
      while (gameRunning)
      {
        delay = INITIAL_DELAY - (snakeLength - 5) * 10;
        if (delay < 20)
          delay = 20;
        // 多次读取输入缓冲区，捕获所有按键
        bool escPressed = false;
        int ch;
        bool r_held = r_pressed; // 保存长按状态
        bool s_held = s_pressed;
        while ((ch = getch()) != ERR)
        {
          if (ch == 27) // ESC 键
          {
            escPressed = true;
            break;
          }
          keyboardControl(ch); // 处理每个输入
          // 按下方向键后清除“按方向键开始移动”提示
          if (ch == KEY_UP || ch == KEY_DOWN || ch == KEY_LEFT || ch == KEY_RIGHT)
          {
            isMoving = true;
            mvprintw(maxY, 1, "                        "); // 清除最底部的提示
            refresh();
          }
        }
        // 恢复长按状态
        r_pressed = r_held;
        s_pressed = s_held;
        // 如果 r 或 s 仍被按住，继续加速/减速
        keyboardControl(ERR);
        if (isMoving)
          snakemove();        // 只有 isMoving 为 true 时移动
        usleep(delay * 1000); // 微秒延迟
        // 延迟碰撞检测，防止初始误判
        static int initialDelay = 5; // 跳过前5帧碰撞检查
        if (initialDelay > 0)
        {
          initialDelay--;
        }
        else if (biteself() || cantcrosswall() || escPressed)
        {
          // 更新最高分
          bool newRecord = false;
          if (currScore > initialHighScore)
          {
            newRecord = true;
            HighScore = currScore; // 立即更新 HighScore
            FILE *file = fopen("save.txt", "w");
            if (file)
            {
              fprintf(file, "%d", currScore);
              fclose(file);
            }
          }
          showGameOver(initialHighScore, newRecord, gameRunning);
          initialHighScore = HighScore; // 更新初始最高分
          initialDelay = 5;             // 重置碰撞检测延迟
        }
      }
      // 如果 gameRunning 为 false，显示主菜单
      printsnake();
      mvprintw(menuY, menuX, "1. 开始游戏");
      mvprintw(menuY + 1, menuX, "2. 游戏说明");
      mvprintw(menuY + 2, menuX, "3. 查看最高分");
      mvprintw(menuY + 3, menuX, "4. 退出");
      mvprintw(menuY + 5, menuX, "请输入你的选择(1-4): ");
      refresh();
    }
    else if (choice == '2')
    {
      explation(false);
      printsnake();
      mvprintw(menuY, menuX, "1. 开始游戏");
      mvprintw(menuY + 1, menuX, "2. 游戏说明");
      mvprintw(menuY + 2, menuX, "3. 查看最高分");
      mvprintw(menuY + 3, menuX, "4. 退出");
      mvprintw(menuY + 5, menuX, "请输入你的选择(1-4): ");
      refresh();
    }
    else if (choice == '3')
    {
      showRank();
      printsnake();
      mvprintw(menuY, menuX, "1. 开始游戏");
      mvprintw(menuY + 1, menuX, "2. 游戏说明");
      mvprintw(menuY + 2, menuX, "3. 查看最高分");
      mvprintw(menuY + 3, menuX, "4. 退出");
      mvprintw(menuY + 5, menuX, "请输入你的选择(1-4): ");
      refresh();
    }
    else if (choice == '4')
    {
      clear();
      mvprintw(maxY / 2, maxX / 4, "感谢游玩，再见！2");
      refresh();
      usleep(1000000);
      mvprintw(maxY / 2, maxX / 4, "感谢游玩，再见！1");
      refresh();
      usleep(1000000);
      endwin();
      exit(0);
    }
    else
    {
      mvprintw(menuY + 7, menuX, "输入错误，请按任意键返回！");
      refresh();
      nodelay(stdscr, FALSE); // 等待按键
      getch();
      nodelay(stdscr, TRUE);
      printsnake();
      mvprintw(menuY, menuX, "1. 开始游戏");
      mvprintw(menuY + 1, menuX, "2. 游戏说明");
      mvprintw(menuY + 2, menuX, "3. 查看最高分");
      mvprintw(menuY + 3, menuX, "4. 退出");
      mvprintw(menuY + 5, menuX, "请输入你的选择(1-4): ");
      refresh();
    }
  }
}